package com.aiyige.utils.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;

import com.aiyige.R;
import com.aiyige.page.detail.decoration.MyRecyclerViewDivider;
import com.aiyige.utils.ErrorUtil;
import com.aiyige.utils.RetrofitUtil;
import com.aiyige.utils.UIHelper;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.loadmore.LoadMoreView;

import java.util.LinkedList;
import java.util.List;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Response;

/**
 * Created by zhuyakun on 2017/10/17.
 */

public class GridCommonDataView extends FrameLayout {
    RecyclerView cdvRecyclerView;
    SwipeRefreshLayout cdvSwipeRefreshLayout;
    ImageView cdvBackToTopBtn;
    View cdvLoadingLayout;
    View cdvErrorLayout;
    BaseQuickAdapter cdvAdapter;
    long page = 0;
    boolean lastPage = false;
    Handler mainHandler;
    GridLayoutManager layoutManager;
    RetrofitStub cdvRetrofitStub;
    int errorLayoutResId;
    int loadingLayoutResId;
    int emptyLayoutResId;
    int spanCount;
    volatile boolean requestingData = false;
    ErrorHandler errorHandler = null;
    UserActionCallback actionCallback = null;
    boolean disableManualRefresh = true;
    boolean autoHideFooter = false;
    LoadMoreView loadMoreView = null;
    View emptyView = null;

    public GridCommonDataView(@NonNull Context context) {
        super(context);
        init(null);
    }

    public GridCommonDataView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public GridCommonDataView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    public LoadMoreView getLoadMoreView() {
        return loadMoreView;
    }

    public void setLoadMoreView(LoadMoreView loadMoreView) {
        this.loadMoreView = loadMoreView;
    }

    public View getEmptyView() {
        return emptyView;
    }

    public void setEmptyView(View emptyView) {
        this.emptyView = emptyView;
    }

    private void init(AttributeSet attrs) {
        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.GridCommonDataView);
            errorLayoutResId = a.getResourceId(R.styleable.GridCommonDataView_gcdv_error_layout, R.layout.standard_error_layout);
            loadingLayoutResId = a.getResourceId(R.styleable.GridCommonDataView_gcdv_loading_layout, R.layout.standard_loading_layout);
            emptyLayoutResId = a.getResourceId(R.styleable.GridCommonDataView_gcdv_empty_layout, R.layout.standard_empty_layout);
            disableManualRefresh = a.getBoolean(R.styleable.GridCommonDataView_gcdv_disable_manual_refresh, false);
            autoHideFooter = a.getBoolean(R.styleable.GridCommonDataView_gcdv_auto_hide_footer, false);
            spanCount = a.getInteger(R.styleable.GridCommonDataView_gcdv_span_count, 4);
            a.recycle();
        } else {
            disableManualRefresh = false;
            errorLayoutResId = R.layout.standard_error_layout;
            loadingLayoutResId = R.layout.standard_loading_layout;
            emptyLayoutResId = R.layout.standard_empty_layout;
            autoHideFooter = false;
            spanCount = 4;
        }
        LayoutInflater.from(getContext()).inflate(R.layout.grid_common_data_view, this, true);
        cdvRecyclerView = (RecyclerView) findViewById(R.id.cdv_recyclerView);
        cdvSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.cdv_swipeRefreshLayout);
        cdvBackToTopBtn = (ImageView) findViewById(R.id.cdv_backToTopBtn);


        cdvErrorLayout = LayoutInflater.from(getContext()).inflate(errorLayoutResId, this, false);
        cdvErrorLayout.setVisibility(INVISIBLE);
        addView(cdvErrorLayout);
        cdvLoadingLayout = LayoutInflater.from(getContext()).inflate(loadingLayoutResId, this, false);
        cdvLoadingLayout.setVisibility(VISIBLE);
        addView(cdvLoadingLayout);
        cdvAdapter = null;

        mainHandler = new Handler(Looper.getMainLooper());
        layoutManager = new GridLayoutManager(getContext(), spanCount);
        cdvRecyclerView.setLayoutManager(layoutManager);
        cdvRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                if (layoutManager.findFirstVisibleItemPosition() < 10 * spanCount) {
                    cdvBackToTopBtn.setVisibility(View.INVISIBLE);
                } else {
                    cdvBackToTopBtn.setVisibility(View.VISIBLE);
                }
            }
        });
        cdvErrorLayout.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                showLoadingLayout();
                doRefreshRequest();
            }
        });
        cdvSwipeRefreshLayout.setEnabled(!disableManualRefresh);
        cdvBackToTopBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                backToTop(true);
            }
        });
    }


    public void backToTop(boolean animated) {
        if (animated) {
            int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
            if (firstVisibleItemPosition <= 5 * spanCount) {
                cdvRecyclerView.smoothScrollToPosition(0);
            } else {
                cdvRecyclerView.scrollToPosition(5 * spanCount);
                cdvRecyclerView.smoothScrollToPosition(0);
            }
        } else {
            cdvRecyclerView.scrollToPosition(0);
        }
    }


    public void addItemDecoration(int dp, int colorId) {
        if (cdvRecyclerView != null) {
            cdvRecyclerView.addItemDecoration(new MyRecyclerViewDivider(
                    getContext(), LinearLayoutManager.VERTICAL, UIHelper.dip2px(getContext(), dp), colorId));
        }
    }

    public RecyclerView getRecyclerView() {
        return cdvRecyclerView;
    }

    public void config(BaseQuickAdapter baseQuickAdapter, RetrofitStub retrofitStub) {
        cdvAdapter = baseQuickAdapter;
        cdvRetrofitStub = retrofitStub;
        if (emptyView == null) {
            cdvAdapter.setEmptyView(LayoutInflater.from(getContext()).inflate(emptyLayoutResId, cdvRecyclerView, false));
        } else {
            cdvAdapter.setEmptyView(emptyView);
        }
        cdvRecyclerView.setAdapter(cdvAdapter);
        if (cdvRetrofitStub != null) {
            if (loadMoreView == null) {
                cdvAdapter.setLoadMoreView(new LoadMoreView() {
                    @Override
                    public int getLayoutId() {
                        return R.layout.standard_load_more_view;
                    }

                    @Override
                    protected int getLoadingViewId() {
                        return R.id.load_more_loading_view;
                    }

                    @Override
                    protected int getLoadFailViewId() {
                        return R.id.load_more_load_fail_view;
                    }

                    @Override
                    protected int getLoadEndViewId() {
                        return R.id.load_more_load_end_view;
                    }
                });
            } else {
                cdvAdapter.setLoadMoreView(loadMoreView);
            }
            cdvSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                @Override
                public void onRefresh() {
                    doRefreshRequest();
                    if (actionCallback != null) {
                        actionCallback.onUserRefresh();
                    }
                }
            });
            cdvAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
                @Override
                public void onLoadMoreRequested() {
                    doLoadMoreRequest();
                    if (actionCallback != null) {
                        actionCallback.onUserLoadMore();
                    }
                }
            }, cdvRecyclerView);
        } else {
            hideCoverLayout();
            cdvSwipeRefreshLayout.setEnabled(false);
            cdvAdapter.setEnableLoadMore(false);
        }
    }


    public void showErrorLayout() {
        cdvErrorLayout.setVisibility(View.VISIBLE);
        cdvLoadingLayout.setVisibility(View.INVISIBLE);
    }

    public void showLoadingLayout() {
        cdvErrorLayout.setVisibility(View.INVISIBLE);
        cdvLoadingLayout.setVisibility(View.VISIBLE);
    }

    public void hideCoverLayout() {
        cdvErrorLayout.setVisibility(View.INVISIBLE);
        cdvLoadingLayout.setVisibility(View.INVISIBLE);
    }


    public void doLoadMoreRequest() {
        if (requestingData) return;
        requestingData = true;
        cdvSwipeRefreshLayout.setEnabled(false);
        requestData();
    }

    public void clearRequestState() {
        requestingData = false;
        cdvSwipeRefreshLayout.setRefreshing(false);
        cdvAdapter.setEnableLoadMore(true);
        cdvSwipeRefreshLayout.setEnabled(!disableManualRefresh);
    }

    public ErrorHandler getErrorHandler() {
        return errorHandler;
    }

    public void setErrorHandler(ErrorHandler errorHandler) {
        this.errorHandler = errorHandler;
    }

    public UserActionCallback getActionCallback() {
        return actionCallback;
    }

    public void setActionCallback(UserActionCallback actionCallback) {
        this.actionCallback = actionCallback;
    }

    /***
     * 不带下拉动画
     */
    public void doRefreshRequest() {
        if (requestingData) return;
        requestingData = true;
        page = 0;
        cdvAdapter.setEnableLoadMore(false);
        requestData();
    }

    /***
     * 带下拉动画
     */
    public void refresh() {
        if (requestingData) return;
        cdvSwipeRefreshLayout.setRefreshing(true);
        doRefreshRequest();
    }

    /**
     * 分离加载动画为单独过程，满足一些特殊的先显示动画后刷新的场景
     */
    public void showRefreshing() {
        if (cdvErrorLayout.getVisibility() == View.VISIBLE) {
            showLoadingLayout();
        }
        cdvSwipeRefreshLayout.setRefreshing(!disableManualRefresh);
    }

    public void requestData() {
        if (cdvRetrofitStub == null || cdvRetrofitStub.call(page) == null) {
            return;
        }
        cdvRetrofitStub.call(page).enqueue(new retrofit2.Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    if (!response.isSuccessful()) {
                        throw new Exception(ErrorUtil.extractMessageFromErrorResponse(response));
                    }
                    String json = RetrofitUtil.getResponseBodyAsString(response);
                    List resultList = new LinkedList<>();
                    HandleResult handleResult = cdvRetrofitStub.handleResponse(json, resultList);
                    if (handleResult != null && handleResult.isSuccess()) {
                        if (page == 0) {
                            cdvAdapter.setNewData(resultList);
                        } else {
                            cdvAdapter.addData(resultList);
                        }
                        lastPage = handleResult.isLastPage();
                        if (!lastPage) {
                            cdvAdapter.loadMoreComplete();
                        } else {
                            cdvAdapter.loadMoreEnd(autoHideFooter && (page == 0));
                        }
                        page++;
                        hideCoverLayout();
                        clearRequestState();
                    } else {
                        throw new Exception(handleResult.getMessage());
                    }
                } catch (Exception e) {
                    if (errorHandler != null) {
                        errorHandler.onResponseError(e.getMessage());
                    }
                    onFailure(call, null);
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                if (t != null) {
                    if (errorHandler != null) {
                        errorHandler.onNetError(t.getMessage());
                    }
                }
//                if (!TextUtils.isEmpty(t.getMessage())) {
//                    ToastX.show(getContext(), t.getMessage());
//                }
                if (page == 0) {
                    showErrorLayout();
                } else {
                    cdvAdapter.loadMoreFail();
                }
                clearRequestState();
            }
        });
    }

    public interface ErrorHandler {
        void onResponseError(String errorMsg);

        void onNetError(String errorMsg);
    }

    public interface RetrofitStub {
        Call<ResponseBody> call(long currentPage);

        HandleResult handleResponse(String respJson, List resultList);
    }

    public static class HandleResult {
        boolean success;
        String message;
        boolean lastPage;

        public HandleResult(boolean success, String message, boolean lastPage) {
            this.success = success;
            this.message = message;
            this.lastPage = lastPage;
        }

        public HandleResult(boolean lastPage) {
            this(true, "", lastPage);
        }

        public HandleResult(String message) {
            this(false, message, true);
        }

        public boolean isSuccess() {
            return success;
        }

        public void setSuccess(boolean success) {
            this.success = success;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public boolean isLastPage() {
            return lastPage;
        }

        public void setLastPage(boolean lastPage) {
            this.lastPage = lastPage;
        }
    }

    public void setRecyclerViewBgColor(int color) {
        if (cdvRecyclerView != null) {
            cdvRecyclerView.setBackgroundColor(color);
        }
    }

    public interface UserActionCallback {
        void onUserRefresh();

        void onUserLoadMore();
    }

}
